//
// ql_manager_stub.cc
//

// Note that for the SM component (HW3) the QL is actually a
// simple stub that will allow everything to compile.  Without
// a QL stub, we would need two parsers.

#include <cstdio>
#include <iostream>
#include <sys/times.h>
#include <sys/types.h>
#include <cassert>
#include <cstddef>
#include "tinybase.h"
#include "ql.h"
#include "sm.h"
#include "ix.h"
#include "rm.h"
#include "printer.h"

using namespace std;
int compareAttributes(DataAttrInfo attr1,RelAttr attr2);
int compareValues(void *ldata,void* rdata,AttrType attrType,int length,CompOp compOp);
bool CheckConditionsForAttr(int nConditions,const Condition conditions[],char * Data, int nAttr, DataAttrInfo attrInfo[],int numConditionCheckedWithIndex);

RC CheckCondition(int nConditions, const Condition conditions[],RelCat relcat,DataAttrInfo attrcatData[],int numIndxAttr, int numIndxCond);

//
// QL_Manager::QL_Manager(SM_Manager &smm, IX_Manager &ixm, RM_Manager &rmm)
//
// Constructor for the QL Manager
//
QL_Manager::QL_Manager(SM_Manager &smm, IX_Manager &ixm, RM_Manager &rmm)
{
    this->ix_manager=&ixm;
    this->rm_manager=&rmm;
    this->sm_manager=&smm;
}

//
// QL_Manager::~QL_Manager()
//
// Destructor for the QL Manager
//
QL_Manager::~QL_Manager()
{
}

//
// Handle the select clause
//
RC QL_Manager::Select(int nSelAttrs, const RelAttr selAttrs[],
                      int nRelations, const char * const relations[],
                      int nConditions, const Condition conditions[])
{
    int i;
    RC rc = 0;

        //select * from ...
    DataAttrInfo attributes[nRelations * MAXATTRS];
    int nRelAttrs = 0;
    RM_Record rec;
    RM_FileScan filescan;
    bool relExist = false;
    char * data;

    if(nSelAttrs==1 && selAttrs[0].relName==NULL&&(!strcmp(selAttrs[0].attrName,"*"))){

        if(nRelations == 1 && nConditions == 0){
            rc = sm_manager->Print(relations[0]);
            if( !rc ) return rc;
        }else if(nRelations == 1 && nConditions > 0){

            // on recherche les attributs de la relation
            DataAttrInfoPrinter attrsInfoCat[MAXATTRS];
            int nbreAttributTrouve = 0;// pour arreter la recherche lorsqu'on a recuperer tous les attributs de la relation
            RM_FileHandle  fhAttrcat;

            if( (rc = rm_manager->OpenFile("attrcat", fhAttrcat))  != 0) return rc;

            if((rc = filescan.OpenScan(fhAttrcat, INT, sizeof(int), 0, NO_OP , NULL)) != 0) return rc;
            rc = filescan.GetNextRec(rec);
            while(rc!=RM_EOF){



                if(rc != 0) return rc;
                if((rc = rec.GetData(data)) != 0) return rc;
                if(!strcmp(((AttrCat*)data)->relName,relations[0])) {

                    strcpy(attrsInfoCat[nbreAttributTrouve].relName, ((AttrCat*)data)->relName);
                    strcpy(attrsInfoCat[nbreAttributTrouve].attrName, ((AttrCat*)data)->attrName);
                    attrsInfoCat[nbreAttributTrouve].attrType = ((AttrCat*)data)->attrType;
                    attrsInfoCat[nbreAttributTrouve].attrLength = ((AttrCat*)data)->attrLength;
                    attrsInfoCat[nbreAttributTrouve].offset = ((AttrCat*)data)->offset;
                    attrsInfoCat[nbreAttributTrouve].indexNo = ((AttrCat*)data)->indexNo;
                    nbreAttributTrouve++;
                }

                rc = filescan.GetNextRec(rec);
            }
            if((rc = filescan.CloseScan()) != 0) return rc;
            rm_manager->CloseFile(fhAttrcat);

            //On cree lobjet printer
            Printer pr(attrsInfoCat, nbreAttributTrouve);

            //Imprimer le contenu du tableau
            //il faut scanner tout le tableau
            RM_FileHandle rmFileHandle;
            // ouverture de la relation pour lire les donnees
            if((rc = rm_manager->OpenFile(relations[0], rmFileHandle)) != 0) return rc;

            int pos = 0;


            for(pos = 0; pos < nbreAttributTrouve; pos ++)

                if( strcmp(conditions[0].lhsAttr.attrName, attrsInfoCat[pos].attrName) == 0){

                    break;

                }

            if((rc = filescan.OpenScan(rmFileHandle, conditions[0].rhsValue.type, attrsInfoCat[pos].attrLength, attrsInfoCat[pos].offset, EQ_OP , conditions[0].rhsValue.data)) != 0 ) return rc;

            //Imprimer le header
            pr.PrintHeader(cout);

            rc = filescan.GetNextRec(rec);
            while(rc!=RM_EOF)
            {

                if(rc != 0) return rc;
                if((rc = rec.GetData(data)) != 0) return rc;

                pr.Print(cout,data);
                rc = filescan.GetNextRec(rec);

            }
            //printing the footer
            pr.PrintFooter(cout);



        }

//        RM_FileHandle  fhAttrcat;

//        if( (rc = rm_manager->OpenFile("attrcat", fhAttrcat))  != 0) return rc;

//        for(int j=0;j<nRelations;j++){
//            DataAttrInfo attrOfRel[MAXATTRS];
//            int nAttrOfRel=0;
//            getDataAttributs(relations[j],attrOfRel,nAttrOfRel, fhAttrcat);
//            memcpy(attributes+nRelAttrs,attrOfRel,nAttrOfRel*sizeof(DataAttrInfo));
//            nRelAttrs += nAttrOfRel;
//        }

//        for(int j = 0; j < nRelAttrs; j ++){
//            cout << "   attributes[" << j << "]:" << attributes[j].relName << attributes[j].attrName  << attributes[j].indexNo << "\n";
//        }
//        rm_manager->CloseFile(fhAttrcat);



    }

    return rc;
}

//
// Insert the values into relName
//
RC QL_Manager::Insert(const char *relName,
                      int nValues, const Value values[])
{


    int i;
    cout << "Insert\n";

    cout << "   relName = " << relName << "\n";
    cout << "   nValues = " << nValues << "\n";
    for (i = 0; i < nValues; i++)
        cout << "   values[" << i << "]:" << values[i] << "\n";

    RC rc;
    RelCat relcat;
    RID rid;

    // Plan du insert:
    // 1. Vérification que la table n'est pas RELCAT ou ATTRCAT
    if(!strcmp(relName,"ATTRCAT") || !strcmp(relName,"RELCAT"))
        return QL_INVALIDRELNAME;

    // 2. Vérification que la table relName existe   
    if( rc=sm_manager->GetCurrRelTuple(relName,relcat,rid))
        return QL_RELATIONDONOTEXIST;

    // 3. Vérification du nombre d'attributs
    if(nValues != relcat.attrNb)
        return QL_WRONGATTRIBUTECOUNT;

    // 4. Vérification du type et de la taille des attributs pour chaque attribut
    DataAttrInfo attrData[relcat.attrNb];
    rc = GetAllAttributeInfo(relName,relcat,attrData);
    if(rc)
        return rc;

    for(i=0;i<relcat.attrNb;i++) {
        if(attrData[i].attrType != values[i].type)
            return QL_WRONGATTRIBUTETYPE;
        if(attrData[i].attrLength < strlen((char*)values[i].data))
            // TODO: ce check laisse passer des trop grandes valeurs de float ou int.           
            return QL_ATTRIBUTETOOBIG;
    }

    // 5. Construction de la data du tuple
    char recordData[relcat.recordLength];
    char* recordDataPtr = recordData;
    for(i=0;i<relcat.attrNb;i++) {
        memmove(recordDataPtr,(char*)values[i].data,attrData[i].attrLength);
        recordDataPtr = recordDataPtr + attrData[i].attrLength;
    }

    // 6. Insertion du tuple avec InsertRec
    RID recordRID;
    RM_FileHandle recordFileHandle;
    if(rc = this->rm_manager->OpenFile(relName,recordFileHandle))
        return rc;
    if(rc = recordFileHandle.InsertRec(recordData,recordRID))
        return rc;

    // 7. Enregistrement du tuple sur disque avec ForcePages et fermeture du fichier
    if(rc = recordFileHandle.ForcePages())
        return rc;
    if(rc = this->rm_manager->CloseFile(recordFileHandle))
        return rc;

    // 8. Pour chaque attribut, recherche d'un index et si existe, ouverture, insertion, forcepages et fermeture
    IX_IndexHandle indexHandle;
    for(i=0;i<relcat.attrNb;i++) {
        if(attrData[i].indexNo != -1) {
            if(rc =  this->ix_manager->OpenIndex(relName,attrData[i].indexNo,indexHandle))
                return rc;
            if(rc = indexHandle.InsertEntry(values[i].data,recordRID))
                return rc;
            if(rc = indexHandle.ForcePages())
                return rc;
            if (rc = this->ix_manager->CloseIndex(indexHandle))
                return rc;
        }
    }

    return 0;

}

//
// Delete from the relName all tuples that satisfy conditions
//
RC QL_Manager::Delete(const char *relName,
                      int nConditions, const Condition conditions[])
{
    int i;

    cout << "Delete\n";

    cout << "   relName = " << relName << "\n";
    cout << "   nCondtions = " << nConditions << "\n";
    for (i = 0; i < nConditions; i++)
        cout << "   conditions[" << i << "]:" << conditions[i] << "\n";

    RC rc;

            RM_Record rec;

            IX_IndexHandle ixh1;
            IX_IndexHandle ixh2;
            IX_IndexScan ixis;

            RelCat relcat;
            RM_FileHandle rmfh;
            RM_FileScan rmfs;

            int count=0;

            RID rid;
            RID rid1;

            char * Data;
            char * Data1;

            void * value=NULL;


            int numIndexAttr=-1;
            int numIndexCond=-1;

            PageNum p;
            SlotNum s;





            // Sanity Check: relName should not be RELCAT or ATTRCAT
            if (strcmp(relName, "relcat") == 0 || strcmp(relName, "attrcat") == 0) {
               return QL_INVALIDRELNAME;
            }

            // Sanity Check: relation should exist

            rc=sm_manager->GetCurrRelTuple(relName,relcat,rid);
            if(rc!=0)
                return QL_RELATIONDONOTEXIST;



            DataAttrInfo attrcatData[relcat.attrNb];
            rc = GetAllAttributeInfo(relName,relcat,attrcatData);
            if(rc!=0)
                return (rc);

            // pas de conditions
            if(nConditions==0)
                {

                cout << "Full scan de la table " << relName << endl;
                cout << "        Suppression de tous les tuples" << endl;

                cout << endl;
                cout << endl;
                rc = rm_manager->OpenFile(relName, rmfh);
                if (rc != 0)
                    return rc;

                rc=rmfs.OpenScan(rmfh,INT,4,0,NO_OP,value,NO_HINT);
                if(rc!=0)
                    return rc;

                rc=rmfs.GetNextRec(rec);

                if (rc!=0 && rc!=RM_EOF)
                    return (rc);

                while(rc!= RM_EOF)
                {

                rc = rec.GetRid(rid);
                if (rc != 0)
                    return rc;

                rid.GetPageNum(p);
                rid.GetSlotNum(s);
                rid1 = RID(p, s);
                rc = rec.GetData(Data);
                if (rc != 0)
                    return rc;


    //supprimer les index entries
                    for(int i=0;i<relcat.attrNb;i++)
                    {
                        if(attrcatData[i].indexNo!=-1)
                        {
                            rc=ix_manager->OpenIndex(relName,attrcatData[i].indexNo,ixh1);
                            if(rc!=0)
                                return rc;

                            Data1=Data+attrcatData[i].offset;


                           rc=ixh1.DeleteEntry(Data1,rid);
                            if(rc!=0)
                                return rc;

                            rc=ixh1.ForcePages();
                            if(rc!=0)
                                return rc;

                            rc=ix_manager->CloseIndex(ixh1);
                            if(rc!=0)
                                return rc;

                        }
                    }

                    rc = rmfh.DeleteRec(rid1);
                    if (rc != 0)
                    return rc;

                    rc=rmfs.GetNextRec(rec);

                }

                rc=rmfs.CloseScan();
                if(rc!=0)
                    return rc;


                rc=rmfh.ForcePages(ALL_PAGES);
                if(rc!=0)
                    return rc;

                rc=rm_manager->CloseFile(rmfh);
                if(rc!=0)
                    return rc;
            }

            // conditions
            else
            {
                rc= CheckCondition(nConditions,conditions,relcat,attrcatData,numIndexAttr,numIndexCond);
                if(rc)
                    return rc;

                // si aucun index sur les attribut de la condition
                if(numIndexAttr==-1)
                {
                    count=0;

                    rc=rm_manager->OpenFile(relName,rmfh);
                    if(rc!=0)
                        return rc;

                    rc=rmfs.OpenScan(rmfh,INT,4,0,NO_OP,value,NO_HINT);
                    if(rc!=0)
                        return rc;

                    rc=rmfs.GetNextRec(rec);

                    if (rc!=0 && rc!=RM_EOF)
                        return (rc);

                    while(rc!= RM_EOF)
                    {

                        rc=rec.GetData(Data);
                        if(rc!=0)
                            return rc;

                        if(CheckConditionsForAttr(nConditions,conditions,Data,relcat.attrNb,attrcatData,numIndexCond))
                         {
                            count++;
                            if(count!=1)
                            {
                                rc=rmfh.DeleteRec(rid1);
                                if(rc!=0)
                                    return rc;
                            }

                            rc=rec.GetRid(rid);
                            if(rc!=0)
                                return rc;

                            rid.GetPageNum(p);
                            rid.GetSlotNum(s);

                            rid1 = RID(p,s);


                            for(int i=0;i<relcat.attrNb;i++)
                            {
                                if(attrcatData[i].indexNo!=-1)
                                {
                                    rc=ix_manager->OpenIndex(relName,attrcatData[i].indexNo,ixh1);
                                    if(rc!=0)
                                        return rc;

                                    Data1=Data+attrcatData[i].offset;


                                    rc=ixh1.DeleteEntry(Data1,rid);
                                    if(rc!=0)
                                        return rc;

                                    rc=ixh1.ForcePages();
                                    if(rc!=0)
                                        return rc;

                                    rc=ix_manager->CloseIndex(ixh1);
                                    if(rc!=0)
                                        return rc;
                                }
                            }
                       }

                        rc=rmfs.GetNextRec(rec);
                    }

                    rc=rmfs.CloseScan();
                    if(rc!=0)
                        return rc;

                    if(p!=-1)
                    {
                        rc=rmfh.DeleteRec(rid1);
                        if(rc!=0)
                            return rc;
                    }

                    rc=rmfh.ForcePages(ALL_PAGES);
                    if(rc!=0)
                        return rc;

                    rc=rm_manager->CloseFile(rmfh);
                    if(rc!=0)
                        return rc;


                }


                // Au moin un attribut possede un index
                else
                {
                    count=0;
                    p=-1;


                    rc=rm_manager->OpenFile(relName,rmfh);
                    if(rc!=0)
                        return rc;

                    rc=ix_manager->OpenIndex(relName,attrcatData[numIndexAttr].indexNo,ixh1);
                    if(rc!=0)
                        return rc;

                    rc=ixis.OpenScan (ixh1,conditions[numIndexCond].op, conditions[numIndexCond].rhsValue.data, NO_HINT);// ouverture d'un scan sur l'index
                    if(rc!=0)
                        return rc;

                    rc=ixis.GetNextEntry(rid);
                    if (rc!=0 && rc!=IX_EOF)
                        return (rc);

                    while(rc!=IX_EOF)
                    {
                        rc=rmfh.GetRec(rid,rec);
                        if(rc!=0)
                            return rc;

                        rc=rec.GetData(Data);
                        if(rc!=0)
                            return rc;

                        if(CheckConditionsForAttr(nConditions,conditions,Data,relcat.attrNb,attrcatData,numIndexCond)) // verification du reste des conditions
                         {
                            for(int i=0;i<relcat.attrNb;i++)
                            {
                                if((attrcatData[i].indexNo!=-1))
                                {
                                    rc=ix_manager->OpenIndex(relName,attrcatData[i].indexNo,ixh2);
                                    if(rc!=0)
                                        return rc;

                                    Data1=Data+attrcatData[i].offset;


                                    rc=ixh2.DeleteEntry(Data1,rid); // suppression du tuple des differents indexs
                                    if(rc!=0)
                                        return rc;

                                    rc=ixh2.ForcePages();
                                    if(rc!=0)
                                        return rc;

                                    rc=ix_manager->CloseIndex(ixh2);
                                    if(rc!=0)
                                        return rc;
                                }
                            }
                            rc=rmfh.DeleteRec(rid);// .. et de la relation
                            if(rc!=0)
                                return rc;
                         }
                        rc=ixis.GetNextEntry(rid);
                    }

                    rc=ixis.CloseScan();
                    if(rc!=0)
                        return rc;

                    rc=rm_manager->CloseFile(rmfh);
                    if(rc!=0)
                        return rc;

                    rc=ix_manager->CloseIndex(ixh1);
                    if(rc!=0)
                        return rc;

                }
            }

                return 0;


}


//
// Update from the relName all tuples that satisfy conditions
//
RC QL_Manager::Update(const char *relName,
                      const RelAttr &updAttr,
                      const int bIsValue,
                      const RelAttr &rhsRelAttr,
                      const Value &rhsValue,
                      int nConditions, const Condition conditions[])
{
        RC rc = 0;
        RM_FileHandle fhRelcat, fhAttrcat;

    //ouvrir les fichier contenant les catalogues de la BD
    rc = rm_manager->OpenFile("relcat", fhRelcat);
    if (rc)
        return rc;

    rc = rm_manager->OpenFile("attrcat", fhAttrcat);
    if (rc)
        return rc;

    int i;

    cout << "Update\n";

    cout << "   relName = " << relName << "\n";
    cout << "   updAttr:" << updAttr << "\n";
    if (bIsValue)
        cout << "   rhs is value: " << rhsValue << "\n";
    else
        cout << "   rhs is attribute: " << rhsRelAttr << "\n";

    cout << "   nCondtions = " << nConditions << "\n";
    for (i = 0; i < nConditions; i++)
        cout << "   conditions[" << i << "]:" << conditions[i] << "\n";

    //sans indexage sans jointure une seule condition , bIsValue

cout<<"debug update 1\n";

    //on recherche la relation dans le catalogue
    RM_Record rec;
    RM_FileScan filescan;
    bool relExist = false;
    char * data;
    RelCat relCatInfo;

    if((rc = filescan.OpenScan(fhRelcat, INT, sizeof(int), 0, NO_OP , NULL)) != 0 ) return rc;

    rc = filescan.GetNextRec(rec);

    cout<<"debug update 2\n";
    while(rc != RM_EOF){

        if(rc != 0 ) return rc;

        if((rc = rec.GetData(data)) != 0) return rc;
        if(!strcmp(((RelCat*)data)->relName,relName)) {
            relExist=true;
           // relCatInfo = (RelCat*)data;
             memcpy(&relCatInfo, data, sizeof(RelCat));
            break;
             cout<<"debug update 3\n";
        }

        rc=filescan.GetNextRec(rec);
    }

    cout<<"debug update 4\n";

    // la relation n existe pas: on retourne
    if(!relExist) return (SM_INVALIDRELNAME);

cout<<"debug update 5\n";

    if((rc=filescan.CloseScan()) != 0) return rc;

    // on recherche les attributs de la relation
    int foundAt=-1,foundrhsAt=-1;
    DataAttrInfo attrsInfoCat[ relCatInfo.attrNb];
    DataAttrInfo conditionAttributes[nConditions];
    DataAttrInfo rhsConditionAttributes[nConditions];
    int conditionAttributesFound=0;
    int nbrConditionRhs=0;
    int rhsConAttrFound=0;
    int nbreAttributTrouve = 0;// pour arreter la recherche lorsqu'on a recuperer tous les attributs de la relation
    if((rc = filescan.OpenScan(fhAttrcat, INT, sizeof(int), 0, NO_OP , NULL)) != 0) return rc;
    rc = filescan.GetNextRec(rec);
    cout<<"debug update 6\n";
    while(rc!=RM_EOF){


cout<<"debug update 7\n";
        if(rc != 0) return rc;
        if((rc = rec.GetData(data)) != 0) return rc;
        cout<<"debug update 7.1\n";
        if(!strcmp(((AttrCat*)data)->relName,relName)) {
cout<<"debug update 7.2\n";
            strcpy(attrsInfoCat[nbreAttributTrouve].relName, ((AttrCat*)data)->relName);
            strcpy(attrsInfoCat[nbreAttributTrouve].attrName, ((AttrCat*)data)->attrName);
            attrsInfoCat[nbreAttributTrouve].attrType = ((AttrCat*)data)->attrType;
            attrsInfoCat[nbreAttributTrouve].attrLength = ((AttrCat*)data)->attrLength;
            attrsInfoCat[nbreAttributTrouve].offset = ((AttrCat*)data)->offset;
            attrsInfoCat[nbreAttributTrouve].indexNo = ((AttrCat*)data)->indexNo;
cout<<"debug update 7.3\n";
            if(foundAt==-1&&compareAttributes(attrsInfoCat[nbreAttributTrouve],updAttr))
                    foundAt=nbreAttributTrouve;
            cout<<"debug update 7.4\n";
            if(!bIsValue)
            {
            if(foundrhsAt==-1&&compareAttributes(attrsInfoCat[nbreAttributTrouve],rhsRelAttr))
                    foundrhsAt=nbreAttributTrouve;
            cout<<"debug update 7.5\n";
            }
            if(nConditions!=0)
            for(int coNum=0;coNum<nConditions;coNum++)
            {cout<<"debug update 7.6\n";
                if(compareAttributes(attrsInfoCat[nbreAttributTrouve],conditions[coNum].lhsAttr))
                {
                    conditionAttributesFound+=1;
                    conditionAttributes[coNum]=attrsInfoCat[nbreAttributTrouve];
                }
                cout<<"debug update 7.7\n";
                if(conditions[coNum].bRhsIsAttr)
                {   if(nbreAttributTrouve==0)
                        nbrConditionRhs+=1;
                    if(compareAttributes(attrsInfoCat[nbreAttributTrouve],conditions[coNum].rhsAttr))
                    {
                        rhsConAttrFound+=1;
                        rhsConditionAttributes[coNum]=attrsInfoCat[nbreAttributTrouve];
                        cout<<"debug update 7.8\n";
                    }
                }
            }
          //  update group set group.gr="group2" where group.name="Dandachi";


            nbreAttributTrouve++;
        }
        if( nbreAttributTrouve == relCatInfo.attrNb ) break;
        rc = filescan.GetNextRec(rec);
    }
    if((rc = filescan.CloseScan()) != 0) return rc;
cout<<"found At="<<foundAt<<" ncr="<<nbrConditionRhs<<" rcaf="<<rhsConAttrFound<<" nConditions="<<nConditions<<" caf="<<conditionAttributesFound<<"\n";
    if(foundAt==-1||(!bIsValue&&foundrhsAt==-1)||nbrConditionRhs!=rhsConAttrFound||nConditions!=conditionAttributesFound)
        return SM_INVALIDATTRNAME;

cout<<"debug update 7\n";
    DataAttrInfo updAttrInfo=attrsInfoCat[foundAt];
    DataAttrInfo rhsAttrInfo;
    cout<<"debug update 8\n";
    if(!bIsValue)
     {rhsAttrInfo=attrsInfoCat[foundrhsAt];

    if(rhsAttrInfo.attrType!=updAttrInfo.attrType)
        return SM_INVALIDATTR;
    }
cout<<"debug update 9\n";
    if(bIsValue)
    {
        if(rhsValue.type!=updAttrInfo.attrType)
            return SM_INVALIDATTR;
    }
cout<<"debug update 10\n";
    for(int coNum=0;coNum<nConditions;coNum++)
    {
        if(conditions[coNum].bRhsIsAttr)
        {
            if(rhsConditionAttributes[coNum].attrType!=conditionAttributes[coNum].attrType)
                return SM_INVALIDATTR;
        }
        else
        {
            if(conditionAttributes[coNum].attrType!=conditions[coNum].rhsValue.type)
                return SM_INVALIDATTR;
        }
        // Sanity Check: compOp
        switch (conditions[coNum].op) {
        case EQ_OP:
        case LT_OP:
        case GT_OP:
        case LE_OP:
        case GE_OP:
        case NE_OP:
        case NO_OP:
           break;

        default:
           return (RM_INVALIDCOMPOP);
        }

    }
    cout<<"debug update 11\n";

  // if(nnbre of conditions >1)
  //      return too many conditions
    // can only do one or 0

    //without searching the index

    //il faut scanner tout le tableau
    RM_FileHandle rmFileHandle;
    // ouverture de la relation pour lire les donnees
    if((rc = rm_manager->OpenFile(relName, rmFileHandle)) != 0) return rc;
    if((rc = filescan.OpenScan(rmFileHandle, INT, sizeof(int), 0, NO_OP , NULL)) != 0 ) return rc;

    rc = filescan.GetNextRec(rec);
cout<<"debug update 12\n";
    int opResult=nConditions;
   // char * pData;

    while(rc!=RM_EOF&&rc!=PF_EOF)
    {   opResult=nConditions;

        if(rc != 0) return rc;

        if((rc = rec.GetData(data)) != 0) return rc;
        for(int coNum=0;coNum<nConditions;coNum++)
        {
            if(conditions[coNum].bRhsIsAttr)
            {
                if(compareValues(data+conditionAttributes[coNum].offset,data+rhsConditionAttributes[coNum].offset,conditionAttributes[coNum].attrType,conditionAttributes[coNum].attrLength,conditions[coNum].op))
                    opResult--;
            }
            else
            {
                if(compareValues(data+conditionAttributes[coNum].offset,conditions[coNum].rhsValue.data,conditionAttributes[coNum].attrType,conditionAttributes[coNum].attrLength,conditions[coNum].op))
                    opResult--;
            }

        }
        cout<<"rec avant is:"<<(char*)data<<"\n";
        if(opResult==0)
        {

            if(!bIsValue)
            {
                cout<<"copying attr \n";
             if(updAttrInfo.attrLength<=rhsAttrInfo.attrLength)
             memcpy(data+updAttrInfo.offset,data+rhsAttrInfo.offset,updAttrInfo.attrLength);
             else
             memcpy(data+updAttrInfo.offset,data+rhsAttrInfo.offset,rhsAttrInfo.attrLength);
             cout<<"rec is:"<<(char*)data<<"\n";
             rmFileHandle.UpdateRec(rec);
            }
            else
            {
            memcpy(data+updAttrInfo.offset,rhsValue.data,updAttrInfo.attrLength);
            cout<<"copying value\n";

            cout<<"rec is:"<<(char*)data<<"\n";
            rmFileHandle.UpdateRec(rec);
            }

        }

        rc = filescan.GetNextRec(rec);

    }


cout<<"debug update 13\n";
rc = rm_manager->CloseFile(fhRelcat);
if (rc)
    return rc;

rc = rm_manager->CloseFile(fhAttrcat);
if (rc)
    return rc;

rc = rm_manager->CloseFile(rmFileHandle);
if (rc)
    return rc;

    return rc;
}

int compareAttributes(DataAttrInfo attr1,RelAttr attr2)
{
    return(strcmp(attr1.attrName,attr2.attrName)==0)&&(strcmp(attr1.relName,attr2.relName)==0);
}

int compareValues(void *ldata,void* rdata,AttrType attrType,int length,CompOp compOp)
{
    int i1,i2;
    float f1,f2;
    int cmp;
    //char * c;
    switch (attrType) {
    case INT:
       memcpy(&i1,
              ldata,
              sizeof(int));
       memcpy(&i2,
              rdata,
              sizeof(int));
       cmp = i1 - i2;
       break;

    case FLOAT:
       memcpy(&f1,
              ldata,
              sizeof(float));
       memcpy(&f2,
              rdata,
              sizeof(float));
       cmp = f1 - f2;
       break;

    case STRING:

        cmp=strcmp((char *)ldata,(char*)rdata);
       break;
    }

    // Make decision according to comparison operator
    if ((compOp == EQ_OP && cmp == 0)
        || (compOp == LT_OP && cmp < 0)
        || (compOp == GT_OP && cmp > 0)
        || (compOp == LE_OP && cmp <= 0)
        || (compOp == GE_OP && cmp >= 0)
        || (compOp == NE_OP && cmp != 0))
       return 1;
    return 0;
}

//
// void QL_PrintError(RC rc)
//
// This function will accept an Error code and output the appropriate
// error.
//
void QL_PrintError(RC rc)
{
    cout << "QL_PrintError\n   rc=" << rc << "\n";
}

RC QL_Manager::GetAllAttributeInfo(const char *relName,RelCat relcatRec,DataAttrInfo attrcatRec[])
{
   RC rc;
   char _relattrName[MAXNAME+1];
   RM_FileScan fs;
   int compteur=0;
   RM_Record rec;
   char* Data;


   // Open a file scan for ATTRCAT
   memset(_relattrName, '\0', sizeof(_relattrName));
   strcpy(_relattrName, relName);

   rc = fs.OpenScan(sm_manager->fhAttrcat, STRING, MAXNAME + 1,offsetof(AttrCat, relName), EQ_OP, (void*) relName, NO_HINT);

   if (rc)
      return rc;

   // Find the matching records
   rc = fs.GetNextRec(rec);
   if(rc!=0 && rc!=RM_EOF)
       return rc;

   while((rc!=RM_EOF)&&(compteur<relcatRec.attrNb))
           {
                   rc=rec.GetData(Data);
                   if(rc!=0){
                        fs.CloseScan();
                        return rc;
                   }

                  // Data=Data-sizeof(char);

                   strcpy(attrcatRec[compteur].relName,((DataAttrInfo*)Data)->relName);
                   strcpy(attrcatRec[compteur].attrName,((DataAttrInfo*)Data)->attrName);
                   attrcatRec[compteur].offset=((DataAttrInfo*)Data)->offset;
                   attrcatRec[compteur].attrType=((DataAttrInfo*)Data)->attrType;
                   attrcatRec[compteur].attrLength=((DataAttrInfo*)Data)->attrLength;
                   attrcatRec[compteur].indexNo=((DataAttrInfo*)Data)->indexNo;
                   cout<<"relname "<<attrcatRec[compteur].attrName<<"\n";

                   compteur++;


                   rc=fs.GetNextRec(rec);
                   if(rc!=0 && rc!=RM_EOF){
                       fs.CloseScan();
                       return rc;
                   }
           }

    rc=fs.CloseScan();
    if(rc!=0)
       return rc;

    // Return ok
   return (0);

}

RC CheckCondition(int nConditions, const Condition conditions[],RelCat relcat,DataAttrInfo attrcatData[],int numIndxAttr, int numIndxCond){
    RC rc=0;
    bool attributCorrect=false;
    bool valeurCorrecte=false;


    for(int i=0;i<nConditions;i++)
         {
             attributCorrect=false;
            valeurCorrecte=false;
             for(int j=0;j<relcat.attrNb;j++)
             {
                 //on v\E9rifier que la condition est correcte  l'attribut de la condition est bien un attribut de la table
                 cout<<"con "<<conditions[i].lhsAttr.attrName<<attrcatData[j].attrName<<"\n";
                 attributCorrect=strcmp(conditions[i].lhsAttr.attrName,attrcatData[j].attrName)==0;

                     if((attrcatData[j].indexNo!=-1)&&(numIndxAttr==-1)&&(conditions[i].op!=NE_OP))
                     {
                         numIndxAttr=j;
                         numIndxCond=i;
                     }
                     //la valeur doit avoir le meme type que l'attribut
                     valeurCorrecte=(attrcatData[j].attrType==conditions[i].rhsValue.type);

                     if(valeurCorrecte&&attributCorrect)
                         break;

//                     switch (attrcatData[j].attrType)
//                     {
//                         case INT:
//                         {
//                             if(conditions[i].rhsValue.type==INT)
//                                 valeurCorrecte=true;
//                         }
//                             break;
//                         case FLOAT:
//                         {
//                             if(conditions[i].rhsValue.type!=STRING)
//                                 valeurCorrecte=true;
//                         }
//                             break;
//                         case STRING:
//                         {
//                             if(conditions[i].rhsValue.type==STRING)
//                                 valeurCorrecte=true;
//                         }
//                             break;
//                     }

                 }
//             if(!attributCorrect||!valeurCorrecte)
//                 break;

             }
             if(!attributCorrect)
                 rc=QL_INCOHERENCECONDITIONATTRIBUT;
             if(!valeurCorrecte)
                 rc=QL_INCOHERENCECONDITIONVALEUR;

              return rc;
         }





//
//Vérification des conditions sur un tupe donné
//
bool CheckConditionsForAttr(int nConditions,const Condition conditions[],char * Data, int nAttr, DataAttrInfo attrInfo[],int numConditionCheckedWithIndex)
{
        int i,j;

        char *pData;
        int resultatComparaison;

        for(i=0;i<nConditions;i++)
        {
                if(i!=numConditionCheckedWithIndex)
                {
                        for(j=0;j<nAttr;j++)
                        {
                                //vérification qu'il s'agit du meme attribut
                                if(strcmp(conditions[i].lhsAttr.attrName,attrInfo[j].attrName)==0)
                                {
                                        //positionnement
                                        pData=Data+attrInfo[j].offset;

                                        //comparaison des valeurs

                                        resultatComparaison=compareValues(pData,conditions[i].rhsValue.data,attrInfo[j].attrType,attrInfo[j].attrLength,conditions[i].op);
                                        if(resultatComparaison){
                                            return true;
                                        }else{
                                            return false;
                                        }



                                }
                        }
                }
        }
        return true;
}


